<?php
class RestRequest extends CModel {
	
	/**
	 * 接口方法
	 * @var string
	 */
	public $method;
	
	/**
	 * 应答数据格式
	 * @var string
	 */
	public $dataType = 'json';
	
	public $params = array();
	
	public function attributeNames() {
		return array('method', 'dataType');
	}
	
	public function rules() {
		return array(
			array('method', 'required'),
			array('dayaType, params', 'safe')
		);
	}
	
	public function response() {
		if($this->validate()) {
			$method = $this->createMethod();
		} else {
			$method = Yii::createComponent(array(
				'class' => 'RequestErrorMethod',
				'model' => $this,
			));
		}
		$method->run();
		$respnse = Yii::createComponent(array(
			'class' => 'RestResponse',
			'method' => $method,
			'request' => $this,
		));
		return $respnse->output();
	}
	
	public function createMethod() {
		
		$alias = $this->method;
		$d = strrpos($alias, '.');
		$package = substr($alias, 0, $d);
		$method = $package ? substr($alias, strlen($package)+1) : $alias;
		$class = ucfirst($method).'Method';
		$method = Yii::createComponent(array(
			'class' => 'application.rest.'.$package.'.'.$class,
			'request' => $this,
			'package' => $package,
		));
		foreach($this->params as $k=>$v) {
			$method->$k = $v;
		}
		return $method;
	}
	
}

class RestResponse {
	public $request;
	public $dataType;
	public $method;
	
	public function getHeader() {
		$m = $this->method;
		return array(
			'method' => $this->request->method,
			'requestTime' => '2012-01-23 12:33:41',
			'responseTime' => '149' /*ms*/,
			'dataSize' => '124' /*bytes*/,
			'hasErrors' => $m->hasErrors(),
			'errorCode' => $m->errorCode,
			'errors' => $m->getErrors(),
		);
	}
	
	public function output() {
		
		$data = array(
			'header' => $this->getHeader(),
			'body' => $this->method->data,
		);
		return $this->format($data);
	}
	
	public function format($data) {
		// 这里做数据的格式化多态
		return CJSON::encode($data);
	}
	
}

abstract class RestMethod extends CModel {
	
	const RESPONSE_TYPE_ARRAY = 'array';
	const RESPONSE_TYPE_STRING = 'string';
	const RESPONSE_TYPE_BOOLEAN = 'boolean';
	const RESPONSE_TYPE_NUMBER = 'number';
	const RESPONSE_TYPE_BINARY = 'binary';
	
	protected $_request;
	
	public $package;
	public $name;
	public $responseType = self::RESPONSE_TYPE_STRING;
	
	public $errorCode;
	
	public $data;
	
	public function setRequest($r) {
		$this->_request = $r;
	}
	
	public function getRequest() {
		return $this->_request;
	}
	
	public function run() {
		
		if($this->validate()) {
			$this->data = $this->runInternal();
		}
		
	}
	
	abstract function runInternal();
	
	public function attributeNames() {
	}
	
}

class RequestErrorMethod extends RestMethod {
	
	public $model;
	
	function runInternal() {
		$this->errorCode = '4001';
		$this->addErrors($this->model->getErrors());
	}

	
}


